#!/usr/bin/env python

####

# @project: UbunTube
# @version = 0.1a
# @site UbunTube http://www.ubuntube.tk
# @copyright (c) 2009 Mohamed Nashmi
# @license http://opensource.org/licenses/gpl-license.php GNU Public License

####

import sys
import os
import fileinput

try:
 	import pygtk
  	pygtk.require("2.0")
except:
  	pass
try:
    import gtk
    import gtk.glade
    import gobject
    import glob
except:
	sys.exit(1)
	
	
from urllib import unquote

import Retriever	
import Player
import Debug
	
class Library(gobject.GObject):
    """Library is the notebook widget of the application. It implements functions to add a new page for a video player
    and removes a page in case a video player is closed.
    
    It inherits GObject to allow for future enhancements to allow signals to be emited."""
    
    def __init__(self, window):
        """Creates the notebook widget from the glade file.
        window: the main Window of the application [instance of Main]
        """
        self.__gobject_init__()
        self.wTree = window.wTree
        self.window = window
        self.noteBook = self.wTree.get_widget("notebook")
    
    def addPage(self, canvas, title):
        """Creates a new notebook page based on a Video Player canvas. The canvas
        holds the Mplayer process.
        
        It also creates the page label which includes a close button
        
        canvas = Video.Player.Canvas
        title = A string to act as the title of the page
        
        returns: An integer pointing to the page number in the notebook
        """
        
        box = gtk.HBox()
        label = gtk.Label(title)
        closeImg = gtk.image_new_from_stock(gtk.STOCK_CLOSE, gtk.ICON_SIZE_MENU)
        closeButton = gtk.Button()
        closeButton.add(closeImg)
        closeButton.set_relief(gtk.RELIEF_NONE)
        box.pack_start(label)
        box.pack_end(closeButton, False, False)
        box.show_all()
        page = self.noteBook.append_page(canvas, box)
        closeButton.connect('clicked', self.closePage, page)
        self.noteBook.show_all()
        return page    
        
    
    def closePage(self, button, page):
        """Closes and removes a page from the notebook. It makes sure mplayer quits before removing the
        page to ensure that Mplayer doesnt run in the background.
        
        button = close button on the page label
        page = The page being closed which would be used to retrieve the video
        
        """
        #video id is 0 based, pages start from 1
        videoID = page - 1
        video =  self.window.library.nowPlaying[videoID]
        del self.window.library.nowPlaying[videoID]
        video.player.videoController.closeVideo()
        self.window.notebook.noteBook.remove_page(video.player.page)
        #try:
        #    video.player.videoController.closeVideo()
        #    Debug.debug("WILL REMOVE")
        #    self.window.notebook.noteBook.remove_page(page)
        #except:
        #    print video.title
#        
        
class List(gobject.GObject):
    """List is the most important Class in the application. It contains all the videos
    that have been imported or downloaded. It is the essential library in the application."""
    
    TARGETS = [
            ('text/plain', 0, 1),
        ]

    def __init__(self, window):
        self.__gobject_init__()
        self.wTree = window.wTree
        self.window = window
        
        #: The gtk.IconView widget retrieved from the glade file
        self.iconView = self.wTree.get_widget("videosList")
        self.iconView.connect("item-activated", self.createPlayer)
        self.iconView.connect("selection-changed", self.showOptions)
        #: The gtk.ListStore widget that will hold the Video rows
        self.model = gtk.ListStore(str, gtk.gdk.Pixbuf)
        self.favoritesModel = gtk.ListStore(str, gtk.gdk.Pixbuf)
        self.iconView.set_text_column(0)
        self.iconView.set_pixbuf_column(1)
        self.iconView.set_model(self.model)
        self.iconView.enable_model_drag_dest(self.TARGETS,gtk.gdk.ACTION_COPY)
        self.iconView.connect("drag_data_received",self.dragDrop)

        #:Videos is a tuple referencing to each Video added to the Library with key of current Id
        self.videos = {}
        self.addedVideos = []
        self.nowPlaying = []
        #: Current Id is used to retrieve videos from the  List.videos tuple
        self.currentId = 0
        
    def dragDrop(self, iconView, context, x, y, selection, info, etime):
        """Handles drag and drop requests to the application. Checks the mime type
        of the file that was dragged. An image becomes the thumbnail of the selected
        video, or a video is added to the library
        """
        fileName = unquote(selection.data)
        fileName = fileName.strip()[7:]
        mime = os.popen("file -i '%s'" % fileName).read()
        mime = mime.split(':')[1]
        
        if "image" in mime:
            model = iconView.get_model()
            drop = iconView.get_dest_item_at_pos(x, y)
            if drop:
                path, position = drop
                videoId = path[0]
                self.changeIcon(videoId, fileName)
        elif "video" in mime:
            self.addVideo(fileName, True)
        else:
            pass

    def showOptions(self, iconView):
        """Hides/Shows the video options from the menu and the top bar. The options are only
        shown when a Video is selected from the Library. Else, its hidden.
        """
        path = self.iconView.get_selected_items()
        videoMenu = self.wTree.get_widget("menu_video")
        menuSetFav = self.wTree.get_widget("menu_set_favorite")
        menuUnsetFav = self.wTree.get_widget("menu_unset_favorite")
        videotoolbarSetFav = self.wTree.get_widget("videotoolbarSetFavorite")
        videotoolbarUnsetFav = self.wTree.get_widget("videotoolbarUnsetFavorite")
        videoToolbar = self.wTree.get_widget("videotoolbar")
        try:
            path = path[0][0]
            videoMenu.set_sensitive(True)
            videoToolbar.show()
            if self.videos[path].favorite:
                menuSetFav.set_sensitive(False)
                videotoolbarSetFav.set_sensitive(False)
                menuUnsetFav.set_sensitive(True)
                videotoolbarUnsetFav.set_sensitive(True)
            else:
                menuSetFav.set_sensitive(True)
                videotoolbarSetFav.set_sensitive(True)
                menuUnsetFav.set_sensitive(False)
                videotoolbarUnsetFav.set_sensitive(False)
        except Exception, e:
            #self.window.topBar.toolbarRemove.hide()
            videoMenu.set_sensitive(False)
            videoToolbar.hide()
        
    def showLibrary(self, sideBar):
        tab = self.window.notebook.noteBook.get_nth_page(0)
        self.window.notebook.noteBook.set_tab_label_text(tab, "Video Library")
        self.iconView.set_model(self.model)
    
    def showFavorites(self, sideBar):
        tab = self.window.notebook.noteBook.get_nth_page(0)
        self.window.notebook.noteBook.set_tab_label_text(tab, "Favorites")
        self.iconView.set_model(self.favoritesModel)
       

    def loadLocalFiles(self):
        """Loads the local files into the library. Videos downloaded or imported
        are copied or linked to from the directory '.library'
        """
        files = open(".files", "r")
        videos = files.readlines()
        files.close
        for localVideo in videos:
            if len(localVideo) > 1:
                videoPath = localVideo.split(',')[0]
                if os.path.exists(videoPath):
                    localVideo = localVideo.strip()
                    self.addVideo(localVideo, True, True)
                else:
                    print localVideo, "doesnt exist"

    def checkExists(self, link):
        """Checks if a video has already been added to the library. Prevent duplicate videos to be 
        added"""
        if link in self.addedVideos:
            md = gtk.MessageDialog(self.window.window, gtk.DIALOG_DESTROY_WITH_PARENT, 
                        gtk.MESSAGE_INFO, gtk.BUTTONS_CLOSE, "File already exists in Library")
            md.run()
            md.destroy()
            return True
            
    def addVideo(self, link, local=False, read=False):
        """Adds a video to the Library. This could be used for either
        a local video or a youtube link.
        
        link = The local path of the file or the Youtube link
        local = Specifies whether the video to be added is local or Youtube lik
        
        Once the Video object is created, it is added to the List.videos tuple
        and the iter is updated in the Video Object
        """
        isFavorite = False
        
        if read:
            videoLine = link
            link, fav = videoLine.split(',')
            if fav == "T":
                isFavorite = True

        if not self.checkExists(link):
            if not local:
                video = Video(link)
            else:
                video = Video(link, True)
            
            video.id = self.currentId
            video.favorite = isFavorite
            self.videos[self.currentId] = video
            self.addedVideos.append(link)
            self.currentId += 1
            video.retriever.start()
            video.connect("updated", self.updateVideoDetails)
            videoDetails = "\n" + video.title + "\n\n" + video.duration
            video.iter = self.model.append([videoDetails, video.thumbnail])
            if isFavorite:
                video.favIter = self.favoritesModel.append([videoDetails, video.thumbnail])
        
    def removeVideo(self, videoID):
        """Removes a video from the library. This removes the video from the Library List
        and from the '.library' directory. If a video is removed, it must be imported or 
        downloaded once again.
        
        videoID = the unique ID of the Video Object to remove
        """
        video = self.videos[videoID]
        self.model.remove(video.iter)
        del self.videos[videoID]
            
    def changeIcon(self, videoID, image):
        """Change the icon of the specified file to an image file chosen by the user. This
        overriedes the screenshot created by mplayer.
        
        videoID = the unique ID of the Video Object to change
        """
        video = self.videos[videoID]
        command = "cp '%s' '%s'" % (image, video.retriever.thumbnail)
        os.system(command)
        video.update(video.retriever)
        
        
        
    def setFavorite(self, videoID):
        video = self.videos[videoID]
        video.favorite = True
        videoDetails = "\n" + video.title + "\n\n" + video.formatDuration
        video.favIter = self.favoritesModel.append([videoDetails, video.thumbnail])
        
        
    def unsetFavorite(self, videoID):
        video = self.videos[videoID]
        video.favorite = False
        self.favoritesModel.remove(video.favIter)
        
    def createPlayer(self, iconView, path):
        """Create a Video Player for the Video Object based on the row number.
        Path is used as the videoID to retrieve the video from the List.videos
        tuple. The page isnt created here, instead it waits for the Player to be
        created and calls the createPlayerPage to create the page
        
        path = The row number of the store
        """
        videoID = path[0]
        openVideo = self.videos[videoID]
        if not openVideo.player:
            print "NO VIDEO"
            player = Player.Mplayer(openVideo)
            openVideo.connect('createdPlayer', self.createPlayerPage)
            openVideo.setPlayer(player)
        else:
            print "Video set already"
            self.createPlayerPage(openVideo)
        
    def createPlayerPage(self, video):
        """Creates a new page for the player and sets the approprate property
        for the Video. After the page is created, the new page is set active"""
        print "CALLING CREATE PLAYER PAGE"
        video.player.UI.show_all()
        video.player.page = self.window.notebook.addPage(video.player.UI, video.title)
        self.nowPlaying.append(video)
        self.window.notebook.noteBook.set_current_page(video.player.page)
        
    def updateVideoDetails(self, video):
        """Updates Video details in the library list. This includes the title
        duration and the thumbnail of the video.
        
        video = Video Object
        """
        vidDetails = "\n" + video.title + "\n\n" + video.formatDuration
        self.model.set_value(video.iter, 0, vidDetails)
        self.model.set_value(video.iter, 1, video.thumbnail)
        
        if video.favorite:
            self.favoritesModel.set_value(video.favIter, 0, vidDetails)
            self.favoritesModel.set_value(video.favIter, 1, video.thumbnail)

class Video(gobject.GObject):
    """Video is inherited from GObject to support emitting signals. Each video added
    to the library is of this Object type. It has a Retrieverobject to download or import
    a file and a Player to play that file.
    """
    __gsignals__ = {
        "updated": (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, ()),
        "createdPlayer" : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, ()),
        }
        
    def __init__(self, link, local=False):
        """Creates the Video Object
        
        link = the YouTube link or the local file path
        local = Indicates whether the file is local or to be retrieved
        """
        self.__gobject_init__()

        #: the youtube link or the local path to the file
        self.link = link 
        #:gtk.TreeIter object poiniting to the location of the Video in the Library Store to ease the removal of the video if necessary
        self.iter = None
        self.favIter = None
        #:Bool value that specifies if the file is local or not
        self.local = local
        #:The Videos Player Object
        self.player = None
        #:The  Videos Unique ID
        self.id = None
        #: The File name of the link or path. Ex: /home/$USER/Ubuntube/test.flv
        self.file = None
        #: The title to be displayed in the Library List
        self.title = None
        #: The duration of the video to be displayed in the Library List
        self.duration = None
        #: The thumbnail of the video to be displayed in the Library List
        self.thumbnail = None
        #: Bool to represent if the video is a favorite
        self.favorite = False
        #:The Videos Retriever Object to download or import the file
        self.retriever = None
        
        if self.local:
            self.retriever = Retriever.Local(self, link)
            self.title = "Importing File..."
            self.retriever.connect("imported", self.update)
        else:
            self.retriever = Retriever.Internet(self, link)
            self.retriever.connect("dataRetrieved", self.update, True)
            self.retriever.connect("downloaded", self.update)
            self.retriever.connect("updateProgress", self.update)
            self.title = "Downloading File..."
        
        self.duration = ""
        self.thumbnail = gtk.gdk.pixbuf_new_from_file(
                                    ".thumbnails/unknown.png"
                                    ).scale_simple(
                                     100,100,gtk.gdk.INTERP_BILINEAR
                                    )

        
        
     
    def setPlayer(self, player):
        """Sets the Videos player to a New Player object and emits the createdPlayer signal. This ensures 
        the video.player isnt None when required to remove."""
        self.player = player
        self.emit("createdPlayer")
        
    def update(self, retriever, internet=False):
        """Updates the information of the file locally. That is, it resets the title,
        duration and thumbnail to more accurate information, rather than the generic
        ones
        
        retriever = Video.Retriever object
        internet = Specifies if this is a Youtube Link
        """
        self.title = retriever.name
        self.file = retriever.file
        self.formatDuration = retriever.formatDuration
        self.duration = retriever.duration
        self.thumbnail = gtk.gdk.pixbuf_new_from_file(
                                    retriever.thumbnail
                                    ).scale_simple(
                                     100,100,gtk.gdk.INTERP_BILINEAR
                                     )
        self.emit('updated')
        if internet:
            retriever.downloadVideo()

gobject.type_register(Video) 
